package king.dominic.jorc.ui;

import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.os.Handler;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.RequiresPermission;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.CompoundButton;

import java.io.File;

import king.dominic.jcamera.CameraCallback;
import king.dominic.jcamera.OCameraPreview;
import king.dominic.jlibrary.fragment.OriginFragment;
import king.dominic.jlibrary.util.FragmentFactory;
import king.dominic.jlibrary.util.PermissionUtil;
import king.dominic.jlibrary.view.WindowUtil;
import king.dominic.jorc.R;
import king.dominic.jorc.core.ErrorCode;
import king.dominic.jorc.core.IdentityCard;
import king.dominic.jorc.core.Listener;
import king.dominic.jorc.core.OCR;

/**
 * Created by DominicKing on 2018/1/23.
 * ParseCardFromCameraFragment
 */

public class ParseCardFromCameraFragment extends OriginFragment {
    private OCameraPreview oCameraPreview;
    private OCR ocr;
    private Handler handler = new Handler();
    private boolean front = true;
    private ScanBoxView scanBoxView;
    private SensorManager sensorManager;
    private Sensor lightSensor;
    private CheckBox checkBox;

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        WindowUtil.fullScreenNow((AppCompatActivity) getActivity());
        return inflater.inflate(R.layout.fragment_parse_card_from_camera, container, false);
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        init();

        oCameraPreview = findViewById(R.id.oCameraPreview);
        scanBoxView = findViewById(R.id.scanBoxView);
        checkBox = findViewById(R.id.checkBox);
        checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                if (oCameraPreview == null) return;
                if (isChecked && !oCameraPreview.isOpenLight()) {
                    oCameraPreview.openLight();
                }
                if (!isChecked && oCameraPreview.isOpenLight()) {
                    oCameraPreview.closeLight();
                }
            }
        });

        scanBoxView.setFront(front);

        ocr = new OCR();

    }

    private long openLightTime = 0;
    // Implement a listener to receive updates
    SensorEventListener listener = new SensorEventListener() {
        @Override
        public void onSensorChanged(SensorEvent event) {
            if (event.values[0] <= 100f) {
                long currentTime = System.currentTimeMillis();
                if (openLightTime == 0) {
                    openLightTime = currentTime;
                }
                if (currentTime - openLightTime > 2000) {
                    if (oCameraPreview.isStart()) {
                        openLightBySensor();
                    }
                }
            } else {
                openLightTime = 0;
            }
        }

        @Override
        public void onAccuracyChanged(Sensor sensor, int accuracy) {

        }
    };

    private void openLightBySensor() {
        unregisterListenerSensor();
        checkBox.setChecked(true);
    }

    private void initSensor() {
        if (oCameraPreview.isOpenLight()) {
            return;
        }
        if (sensorManager == null && lightSensor == null) {
            Context context = getContext();
            if (context == null) return;
            sensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
            if (sensorManager == null) return;
            lightSensor = sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);

            // Register the listener with the light sensor -- choosing
            // one of the SensorManager.SENSOR_DELAY_* constants.
            sensorManager.registerListener(
                    listener, lightSensor, SensorManager.SENSOR_DELAY_UI);
        }
    }

    private void init() {
        Bundle args = getArguments();
        Activity activity = getActivity();
        Object o = args != null ? args.get("front") : (activity != null ? activity.getIntent().getBooleanExtra("front", true) : null);
        front = o == null ? true : (Boolean) o;
    }

    private void start() {
        handler.removeCallbacks(start);
        handler.post(start);
    }

    @Override
    public void onResume() {
        super.onResume();
        PermissionUtil.callMethodNoCallback(this, new String[]{Manifest.permission.CAMERA}, action);

        initSensor();
    }

    @Override
    public void onPause() {
        if (oCameraPreview != null) oCameraPreview.onPause();
        super.onPause();
    }

    private void unregisterListenerSensor() {
        if (sensorManager != null) sensorManager.unregisterListener(listener, lightSensor);
    }

    @Override
    public void onDestroyView() {
        if (ocr != null) ocr.destroy();
        unregisterListenerSensor();
        super.onDestroyView();
    }

    private Runnable action = new Runnable() {
        @Override
        public void run() {
            if (oCameraPreview == null || ocr == null) return;
            Context context = getActivity();
            if (context == null) return;
            if (ActivityCompat.checkSelfPermission(context, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
                return;
            }
            if (!ocr.isInitialize()) {
                ocr.init(getContext(), new Listener.OnSuccessfulListener() {
                    @Override
                    public void success(boolean yes) {
                        start();
                    }
                });
            }
            oCameraPreview.onResume(getActivity());
            start();
        }
    };

    private Runnable start = new Runnable() {
        @Override
        public void run() {

            if (ocr.isInitialize() && (oCameraPreview != null && oCameraPreview.isStart())) {
                oCameraPreview.requestCurrentBitmap(callback);
            }
        }
    };
    private OCR.RecycledBitmap recycledBitmap;
    private CameraCallback callback = new CameraCallback() {
        @Override
        public void response(Bitmap bitmap) {
            if (ocr == null || bitmap == null || bitmap.isRecycled()) {
//                Log.d("ParseCardFromCamera", "response: get bitmap failure~!");
                return;
            }
//            Log.d("ParseCardFromCamera", "response: start parse~!");
            recycledBitmap = new OCR.RecycledBitmap(bitmap, scanBoxView.getRect());
            if (front)
                ocr.parseFrontCard(recycledBitmap, parseCallback);
            else
                ocr.parseBackCard(recycledBitmap, parseCallback);
        }
    };

    private Listener.Callback<Object> parseCallback = new Listener.Callback<Object>() {
        @Override
        public void callback(Object idCard) {
            Log.d("ParseCardFromCamera", "callback: parse " + idCard);
            if (idCard instanceof IdentityCard) {
                Context context = getContext();
                if (context == null) return;
                File file = new File(context.getCacheDir(), "id_card_" + (front ? "front" : "back") + System.currentTimeMillis() + ".jpg");
                recycledBitmap.save(file);
                recycledBitmap.recycled();

                setResult(Activity.RESULT_OK, installCard((IdentityCard) idCard, file.getAbsolutePath(), front));
                finish();

            } else {
                if (recycledBitmap != null)
                    recycledBitmap.autoRecycled();

                showErrorInfo(idCard);
                start();
            }
        }
    };

    private void showErrorInfo(Object info) {
        if (info instanceof Integer) {
            Integer errorCode= (Integer) info;
            if (errorCode == ErrorCode.API_NOT_INIT || errorCode == ErrorCode.BITMAP_USELESS) return;

            if (scanBoxView != null)
                scanBoxView.showErrorBounds(errorCode);

        }
    }

    private static Intent installCard(IdentityCard card, String file, boolean front) {
        Intent intent = new Intent();
        intent.putExtra("IdentityCard", card);
        intent.putExtra("IdentityCardImageFile", file);
        intent.putExtra("IdentityCardFront", front);
        return intent;
    }

    public static IdentityCard obtainCard(Intent data) {
        return (IdentityCard) data.getSerializableExtra("IdentityCard");
    }

    public static String obtainCardImage(Intent data) {
        return data.getStringExtra("IdentityCardImageFile");
    }

    public static boolean obtainCardFront(Intent data) {
        return data.getBooleanExtra("IdentityCardFront", true);
    }

    @SuppressLint("MissingPermission")
    @RequiresPermission(Manifest.permission.CAMERA)
    public static ParseCardFromCameraFragment newInstance(FragmentFactory.FragmentParent parent, boolean front) {
        Bundle args = new Bundle();
        args.putBoolean("front", front);
        return FragmentFactory.obtain(parent, ParseCardFromCameraFragment.class, args);
    }
}
